home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1995 October / EnigmA AMIGA RUN 01 (1995)(G.R. Edizioni)(IT)[!][issue 1995-10][Aminet 7].iso / Aminet / comm / tcp / AmiTCP_mail.lha / mail / mail.c < prev    next >
C/C++ Source or Header  |  1994-03-06  |  10KB  |  468 lines

  1. /*
  2.     Simple SMTP mail sender.
  3.  
  4.     Copyright 1993 Stephen Norris.
  5.  
  6.     $Revision: 1.21 $
  7.  
  8.     $Log: mail.c,v $
  9.  * Revision 1.21  1994/03/06  10:17:03  srn
  10.  * Extended messages are broken - temporary fix.
  11.  *
  12.  * Revision 1.20  1994/02/19  22:33:41  srn
  13.  * Now added: If invoked as sendmail, set NoEd, NoSubj, NoHead.
  14.  *
  15.  * Revision 1.19  1993/12/12  14:20:28  srn
  16.  * Minor changes...
  17.  *
  18.  * Revision 1.18  1993/12/01  09:38:38  srn
  19.  * Checked in for beginning 1.7 release.
  20.  *
  21.  * Revision 1.17  1993/11/30  08:52:02  srn
  22.  * Split up code.
  23.  * Added Reply-To: and MessageId: headers.
  24.  * Tidied up a bit.
  25.  *
  26.  * Revision 1.16  1993/11/24  23:07:23  srn
  27.  * SOrted out NOSIG stuff.
  28.  *
  29.  * Revision 1.15  1993/11/24  22:50:27  srn
  30.  * Removed all SMTPSERVER references.
  31.  *
  32.  * Revision 1.14  1993/11/24  09:53:44  srn
  33.  * Now appends .sig before editing.
  34.  *
  35.  * Revision 1.13  1993/11/22  21:59:53  srn
  36.  * Added editor support.
  37.  *
  38.  * Revision 1.13  1993/11/22  21:59:53  srn
  39.  * Added editor support.
  40.  *
  41.  * Revision 1.12  1993/11/22  19:29:36  srn
  42.  * Added code for sig files.
  43.  *
  44.  * Revision 1.11  1993/11/21  18:04:32  srn
  45.  * Added SIGFILE argument.  Generally tidied up the argument handling.
  46.  *
  47.  * Revision 1.11  1993/11/21  18:04:32  srn
  48.  * Added SIGFILE argument.  Generally tidied up the argument handling.
  49.  *
  50.  * Revision 1.10  1993/11/21  16:48:17  srn
  51.  * Changed multiple destination code.
  52.  *
  53.  * Revision 1.9  1993/11/19  22:20:26  srn
  54.  * Changed order of sender/receiver SMTP messages; hosts
  55.  * require them in a set order.
  56.  * Added a HELO to the start, some smtp demons need it.
  57.  *
  58.  * Revision 1.8  1993/11/17  20:58:36  srn
  59.  * Changed To: lines.
  60.  *
  61.  * Revision 1.7  1993/10/30  09:48:55  srn
  62.  * Copes with multiline responces.
  63.  *
  64.  * Revision 1.6  1993/10/24  11:03:48  srn
  65.  * Does multiple destinations, added date header.
  66.  *
  67.  * Revision 1.6  1993/10/24  11:03:48  srn
  68.  * Does multiple destinations, added date header.
  69.  *
  70.  * Revision 1.5  1993/10/20  22:37:46  srn
  71.  * Working for multiple destinations.
  72.  * Needs to clean up (unlink) the temporary file...
  73.  *
  74.  * Revision 1.4  1993/10/20  20:27:09  srn
  75.  * Got error checking working.
  76.  *
  77.  * Revision 1.3  1993/10/16  11:25:44  srn
  78.  * Compiles.
  79.  *
  80.  * Revision 1.2  1993/10/16  11:19:10  srn
  81.  * Move includes, defines etc. into mail.h
  82.  *
  83. */
  84.  
  85. #include "mail.h"
  86. #include "mail_proto.h"
  87.  
  88. static char *VERSION = "$VER: Mail 1.8 " __AMIGADATE__;
  89.  
  90. int    s;
  91. struct sockaddr_in    Address;
  92. struct hostent    *Hostaddr;
  93. char    *Hostname;
  94. int    Mode;    /* VERBOSE or not. */
  95.  
  96. char    Name[20];    /* Name of the temporary file. */
  97. FILE    *TempMail;    /* The mail is written here, then sent. */
  98.  
  99. char    *ReplyTo;    /* Address to set replies to. */
  100. char    *SigFile;    /* Pathname of .sig file. */
  101.  
  102. /* Flags controlling header generation. */
  103.  
  104. int    NoSubj, NoHead, NoEd, NoSig;    /* No subject line, no headers, no editor, no signature file. */
  105.  
  106. /* Command line options. */
  107.  
  108. static char     Template[] = "RCPT=RECIPIENT/M/A,REPLYTO,SMTPHOST/K,NOSIG/S,VERBOSE/S,NOSUBJ/S,NOHEAD/S,NOED/S";
  109.  
  110. extern int    errno;
  111. extern void    _STDcloseSockets();
  112.  
  113. /* Edit a file for mail. */
  114.  
  115. void
  116. Edit (char *FileName)
  117. {
  118.     char    Command[150];
  119.  
  120.     sprintf(Command, "%s %s", GetEditor(), FileName);
  121.  
  122.     system(Command);
  123. }
  124.  
  125. /* Handle various mailer errors. */
  126.  
  127. void
  128. MailError(int    Type)
  129. {
  130.     if (TempMail){
  131.         /* Should check for existence of t:dead.letter and use a different
  132.            name if it is there.  */
  133.         char    *Fname = "t:dead.letter";
  134.  
  135.         if (rename(Name, Fname) == 0)
  136.             printf("Mail saved in %.\n", Fname);
  137.     }
  138.         
  139.     switch (Type){
  140.         case 0:    /* Look in errno. */
  141.             PrintNetFault(errno, "mail");
  142.             break;
  143.         case BAD_RESPONCE:    /* The server indicated an error.*/
  144.             printf("Error trying to transmit.\n");
  145.             break;
  146.         case NOTEMP:    /* Couldn't open the temporary file. */
  147.             printf("Unable to open the temporary file.\n");
  148.             break;
  149.         }
  150.  
  151.     exit(30);
  152. }
  153.  
  154. /* Now append a signature file, if required and available. */
  155.  
  156. void
  157. AppendSig(FILE *ReadFile, char *SigFile)
  158. {
  159.     FILE     *Sig;
  160.     int    ch;
  161.     char    *SigName;
  162.  
  163.     if (!NoSig){
  164.         if ((SigName = GetSigName()) != NULL){
  165.             if (Sig = fopen (SigName, "r")){
  166.                 while ((ch = fgetc(Sig)) != EOF){
  167.                     fputc(ch, ReadFile);
  168.                 }
  169.             } else 
  170.                 printf("Unable to open signature file.\n");
  171.         }
  172.     }
  173. }
  174.  
  175. /* Read the mail into a temporary file. */
  176.  
  177. FILE *
  178. ReadMail ()
  179. {
  180.     char    Buffer[256];
  181.     FILE *ReadFile;
  182.  
  183.     /* Generate a unique name. */
  184.  
  185.     sprintf(Name, "t:mail.%ld", FindTask(NULL));
  186.  
  187.     if (!(ReadFile = fopen(Name, "w+"))){
  188.         MailError(NOTEMP);
  189.     }
  190.  
  191.     if (!NoSubj && !NoHead){
  192.         printf("Subject: ");
  193.         fgets(Buffer, 255, stdin);
  194.         Buffer[strlen(Buffer) - 1] = (char) 0;
  195.         fputs("Subject: ", ReadFile);
  196.         fputs(Buffer, ReadFile);
  197.         fputs("\n\n", ReadFile);
  198.     }
  199.  
  200.     if (NoEd){
  201.         printf("Now type the text, terminate with EOF or .\n\n");
  202.         /* Read in the body of the mail, and store it in the temporary file. */
  203.         while(!feof(stdin)){
  204.             if (fgets(Buffer, 255, stdin) == NULL)
  205.                 break;
  206.             Buffer[strlen(Buffer) - 1] = (char) 0;
  207.             if (!strcmp(Buffer, "."))
  208.                 break;
  209.             fputs(Buffer, ReadFile);
  210.             fputs("\r\n", ReadFile);
  211.         }
  212.         AppendSig (ReadFile, SigFile);
  213.     } else {
  214.         /* Edit the mail. */
  215.         AppendSig (ReadFile, SigFile);
  216.         fclose(ReadFile);
  217.         Edit (Name);
  218.         if (!(ReadFile = fopen(Name, "r+"))){
  219.             MailError(NOTEMP);
  220.         }
  221.         fseek(ReadFile, 0L, SEEK_END);    /* Go to EOF. */
  222.     }
  223.  
  224.  
  225.     fclose(ReadFile);
  226.  
  227.     printf("[EOT]\n");
  228.  
  229.     if (!(ReadFile = fopen(Name, "r"))){
  230.         MailError(NOTEMP);
  231.     }
  232.     
  233.     return ReadFile;
  234. }
  235.  
  236. /* Simply send some text down the socket; check the write succeeds, but don't
  237. check for any responce. */
  238.  
  239. int
  240. SendText(char *Text)
  241. {
  242.     if (write(s, Text, strlen(Text)) != strlen(Text)){
  243.         MailError(0);
  244.     }
  245.  
  246.     return 1;
  247. }
  248.  
  249. /* Similar to SendText excepting that responces are checked  by comparing them with Expect. */
  250.  
  251. int
  252. SendTextCheck(char *Text, int Expect)
  253. {
  254.     char    Buffer[256];
  255.     int    i;
  256.  
  257.     if ((i = write(s, Text, strlen(Text))) != strlen(Text)){
  258.         MailError(0);
  259.     }
  260.  
  261.     if (read (s, Buffer, 255) <= 5){
  262.         MailError(0);
  263.     }
  264.  
  265.     if (atoi(Buffer) != Expect){
  266.         if (Mode == VERBOSE){
  267.             printf("Got %d, expected %d responce from server.\n", atoi(Buffer), Expect);
  268.             printf("Full text was: %s.\n", Buffer);
  269.             printf("Text sent was: %s.\n", Text);
  270.         }
  271.         MailError(BAD_RESPONCE);
  272.     }
  273.  
  274.     /* Check for, and handle extended messages. */
  275.     /*
  276.     while (Buffer[3] == '-'){
  277.         if (read (s, Buffer, 255) <= 5)
  278.             MailError(0);
  279.     }
  280.     */
  281.  
  282.     return 1;
  283. }
  284.  
  285. /* Send the mail to the recipients.  Send one MAIL FROM:<> and multiple
  286. RCPT TO: messages, followed by DATA.
  287. */
  288.  
  289. int
  290. SendMail(char *Recipients[])
  291. {
  292.     char    *Buffer[BUFSIZE];
  293.     register int    i;
  294.  
  295.  
  296.     rewind(TempMail);
  297.  
  298.     sprintf(Buffer, "MAIL FROM:<%s>\r\n", GetSender());
  299.     SendTextCheck(Buffer, 250);
  300.  
  301.     for (i = 0; Recipients[i] != NULL; i++){
  302.         sprintf(Buffer, "RCPT TO:<%s>\r\n", Recipients[i]);
  303.         SendTextCheck(Buffer, 250);
  304.         if (Mode == VERBOSE)
  305.             printf("Mail being sent to %s.\n", Recipients[i]);
  306.     }
  307.  
  308.     sprintf(Buffer, "DATA\r\n");
  309.     SendTextCheck(Buffer, 354);
  310.  
  311.     /* Produce headers. */
  312.     /* At present there are the following headers:
  313.        Message-Id:
  314.        Reply-To:
  315.        From:
  316.        To:
  317.        Date:
  318.        Subject:
  319.     */
  320.  
  321.     if (!NoHead){
  322.         int    i;
  323.  
  324.         sprintf(Buffer, "Message-Id: <%s.AA%d@%s>\r\n", GetDateId(), FindTask(NULL), GetHostName());
  325.         SendText(Buffer);
  326.  
  327.         sprintf(Buffer, "Reply-To: %s\r\n", ReplyTo);
  328.         SendText(Buffer);
  329.  
  330.         sprintf(Buffer, "From: %s (%s)\r\n", GetSender(), GetRealName());
  331.         SendText(Buffer);
  332.  
  333.         sprintf(Buffer, "Date: %s", GetDate());
  334.         SendText(Buffer);
  335.  
  336.         SendText("To: ");
  337.         for (i = 0; Recipients[i] != NULL; i++){
  338.             sprintf(Buffer,"%s", Recipients[i]);
  339.             if (Recipients[i+1] != NULL)
  340.                 strcat (Buffer, ", ");
  341.             SendText(Buffer);
  342.         }
  343.         SendText("\r\n");
  344.     }
  345.  
  346.     fgets(Buffer, BUFSIZE - 1, TempMail);
  347.     SendText(Buffer);
  348.  
  349.     while (fgets(Buffer, BUFSIZE - 1, TempMail))
  350.         SendText(Buffer);
  351.  
  352.     /* Expecting a "I got that one thanks." type message. */
  353.     SendTextCheck(".\r\n", 250);
  354.  
  355.     if (Mode == VERBOSE)
  356.         printf("Mail is now sent.\n");
  357. }
  358.  
  359. void
  360. main(int argc, char *argv[])
  361. {
  362.     register char    *SMTPHost;
  363.     struct RDArgs    *Args;
  364.     long        ArgRes[ARGCOUNT] = {0, 0, 0};
  365.     register int    i = 0;
  366.  
  367.     /* Look at command line arguments. */
  368.  
  369.     if (!(Args = ReadArgs((UBYTE *)Template, ArgRes, NULL))){
  370.         printf("Usage: %s\n", Template);
  371.         exit(30);
  372.     }
  373.  
  374.     if (ArgRes[VERBOSE]){
  375.         Mode = VERBOSE;
  376.     }
  377.  
  378.     if (ArgRes[REPLYTO]){
  379.         ReplyTo = (char *) ArgRes[1];
  380.     } else {
  381.         ReplyTo = GetSender();
  382.     }
  383.  
  384.     if (ArgRes[SMTPHOST]){
  385.         SMTPHost = (char *) ArgRes[2];
  386.     } else {
  387.         SMTPHost = GetSMTPHost();
  388.     }
  389.  
  390.     NoSig = ArgRes[NOSIG];
  391.     NoSubj = ArgRes[NOSUBJ];
  392.     NoHead = ArgRes[NOHEAD];
  393.  
  394.     NoEd = ArgRes[NOED];
  395.  
  396.     if (strcmp (argv[0], "sendmail") == 0){
  397.         NoSubj = 1;
  398.         NoHead = 1;
  399.         NoEd = 1;
  400.     }
  401.  
  402.     /* Open up the socket.  Pretty standard stuff, cribbed from letnet. */
  403.  
  404.         _STIopenSockets();
  405.     atexit (_STDcloseSockets);
  406.  
  407.         Address.sin_len = sizeof(Address);
  408.         Address.sin_family = AF_INET;
  409.         Address.sin_port = 25;    /* SMTP */
  410.         Address.sin_addr.s_addr = 0;
  411.  
  412.         if (!(Hostaddr = gethostbyname(SMTPHost))){
  413.                 printf("Unknown host.\n");
  414.                 exit(30);
  415.         }
  416.  
  417.     bcopy (Hostaddr->h_addr, (char *) &Address.sin_addr, Hostaddr->h_length);
  418.  
  419.         if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1){
  420.                 PrintNetFault(errno, "socket");
  421.         exit(30);
  422.         }
  423.  
  424.         if (connect (s, (struct sockaddr *) &Address, sizeof(Address)) == -1){
  425.                 PrintNetFault(errno, "connect");
  426.         exit(30);
  427.         }
  428.  
  429.     if (Mode == VERBOSE){
  430.         printf("Connected to %s.\n", SMTPHost);
  431.     }
  432.  
  433.     /* Check we got the "Welcome blah blah" message. */
  434.     SendTextCheck("", 220);
  435.  
  436.     /* Now say HELO like a nice program. */
  437.     {
  438.         char    Temp[108];
  439.  
  440.         if (Mode == VERBOSE){
  441.             printf("HELO\n");
  442.         }
  443.  
  444.         sprintf(Temp, "HELO %s\r\n", GetHostName());
  445.  
  446.         SendTextCheck(Temp, 250);
  447.     }
  448.  
  449.     TempMail = ReadMail();
  450.     
  451.     /* Dispatch the mail. */
  452.  
  453.     SendMail ((char **)ArgRes[0]);
  454.  
  455.     /* Clean up and exit. */
  456.  
  457.     fclose(TempMail);
  458.     unlink(Name);
  459.  
  460.     SendTextCheck("QUIT\r\n", 221);
  461.  
  462.     shutdown(s, 2);
  463.     CloseSocket(s);
  464.     FreeArgs(Args);
  465.  
  466.     exit (0);
  467. }
  468.